#include <common/Logger.h>
#include <fstream>
#include "CmdHandler.h"

void CQueryCmdHandler::writeStatusHeader()
{
    LOCAL_LOGGER(logger,"CQueryCmdHandler::writeStatusHeader");
    DEBUG("open master status file "<<masterStatsFile_);
    std::ofstream outf(masterStatsFile_.c_str());
    if(!outf.is_open()){
        ERROR("cannot open master status file="<<masterStatsFile_);
    }else{
        outf<<"Time"
            <<"\t"<<"RootMetaAddress"
            <<"\t"<<"tableInfo_.Size()"
            <<"\t"<<"updatedTable_.Size()"<<"\t"<<"updatedTable_.TopSize()"
            <<"\t"<<"serverList_.Size()"
            <<"\t"<<"addrIndexMap_.Size()"
            <<"\t"<<"pBusyHeap_.Size()"
            <<"\t"<<"pIdleHeap_.Size()"
            <<"\t"<<"offlineTabletList_.Size()"<<"\t"<<"offlineTabletList_.TopSize()"
            <<"\t"<<"assignTabletList_.Size()"
            <<"\t"<<"quitServer_.Size()"<<"\t"<<"quitServer_.TopSize()"
            <<"\t"<<"CommandStats"
            <<std::endl;
    }
}

void CQueryCmdHandler::writeLoadBalanceHeader()
{
    LOCAL_LOGGER(logger,"CQueryCmdHandler::writeLoadBalanceHeader");
    DEBUG("open load balance file "<<tsLoadBalanceFile_);
    std::ofstream outf(tsLoadBalanceFile_.c_str());
    if(!outf.is_open()){
        ERROR("cannot open load balance file="<<tsLoadBalanceFile_);
    }else{
        outf<<"Time"
            <<"\t"<<"ServerAddress"
            <<"\t"<<"load"
            <<"\t"<<"memoryLoad"
            <<"\t"<<"queryLoad"
            <<"\t"<<"prevQueryLoad"
            <<"\t"<<"capability"
            //info
            <<"\t"<<"totalMemory(KB)"
            <<"\t"<<"freeMemory(KB)"
            <<"\t"<<"cpusLoad"
            <<"\t"<<"inputMessageNumber"
            <<"\t"<<"leftInpuMessageNumber"
            <<"\t"<<"outputMessageNumber"
            <<"\t"<<"leftOutputMessageNumber"
            <<"\t"<<"tabletNumber"
            <<"\t"<<"memoryTableSize(B)"
            <<"\t"<<"cachedBlockSize(B)"
            <<"\t"<<"cachedBlockNumber"
            <<std::endl;
    }
}

void CQueryCmdHandler::writeStatus()
{
    LOCAL_LOGGER(logger,"CQueryCmdHandler::writeStatus");
    DEBUG("open master status file "<<masterStatsFile_<<" and write");
    std::ofstream outf(masterStatsFile_.c_str(),std::ios_base::app);
    if(!outf.is_open()){
        ERROR("cannot open master status file="<<masterStatsFile_);
    }else{
        outf<<Tools::TimeString(time(0));
        outf<<"\t"<<pRootMetaTablet_.ReadPointer()->address_.ToShortString();
        outf<<"\t"<<tableInfo_.Size();
        outf<<"\t"<<updatedTable_.Size()<<"\t"<<updatedTable_.TopSize();
        size_t s1,s2,s3,s4;
        serverList_.GetSizes(s1,s2,s3,s4);
        outf<<"\t"<<s1
            <<"\t"<<s2
            <<"\t"<<s3
            <<"\t"<<s4;
        outf<<"\t"<<offlineTabletList_.Size()<<"\t"<<offlineTabletList_.TopSize();
        outf<<"\t"<<assignTabletList_.Size();
        outf<<"\t"<<quitServer_.Size()<<"\t"<<quitServer_.TopSize();
        {   //Command Stats
            CMutexGuard g(cmdStats_.Mutex());
            for(__CmdStats::iterator it = cmdStats_.begin();it != cmdStats_.end();++it)
                outf<<"\t"<<CommandName(it->first)<<","<<it->second.first<<","<<it->second.second;
            cmdStats_.clear();
        }
        outf<<std::endl;
        outf.close();
        updatedTable_.ResetTopSize();
        offlineTabletList_.ResetTopSize();
        quitServer_.ResetTopSize();
    }
}

void CQueryCmdHandler::writeLoadBalance()
{
    LOCAL_LOGGER(logger,"CQueryCmdHandler::writeLoadBalance");
    DEBUG("open load balance file "<<tsLoadBalanceFile_<<" and write");
    std::ofstream outf(tsLoadBalanceFile_.c_str(),std::ios_base::app);
    if(!outf.is_open()){
        ERROR("cannot load balance status file="<<tsLoadBalanceFile_);
    }else{
        std::vector<CServerInfo> info;
        std::string curtime = Tools::TimeString(time(0));
        serverList_.GetServerInfo(info);
        for(size_t i = 0;i < info.size();++i){
            outf<<curtime
                <<"\t"<<info[i].address_.ToShortString()
                <<"\t"<<(double(info[i].load_.load_) / 10000)
                <<"\t"<<(double(info[i].load_.memoryLoad_) / 10000)
                <<"\t"<<(double(info[i].load_.queryLoad_) / 10000)
                <<"\t"<<(double(info[i].load_.prevQueryLoad_) / 10000)
                <<"\t"<<info[i].load_.capability_
                <<"\t"<<(info[i].load_.totalMemory_ >> 10)
                <<"\t"<<(info[i].load_.freeMemory_ >> 10)
                <<"\t"<<(double(info[i].load_.cpusLoad_) / 100)
                <<"\t"<<info[i].load_.inputMessageNumber_
                <<"\t"<<info[i].load_.leftInpuMessageNumber_
                <<"\t"<<info[i].load_.outputMessageNumber_
                <<"\t"<<info[i].load_.leftOutputMessageNumber_
                <<"\t"<<info[i].load_.tabletNumber_
                <<"\t"<<info[i].load_.memoryTableSize_
                <<"\t"<<info[i].load_.cachedBlockSize_
                <<"\t"<<info[i].load_.cachedBlockNumber_
                <<"\n";

        }
        outf<<"\n";
    }
}

void * CQueryCmdHandler::MasterStatsThread(void * arg)
{
    LOCAL_LOGGER(logger,"CQueryCmdHandler::MasterStatsThread");
    ASSERT(arg != 0,"invalid arg");
    CQueryCmdHandler & self = *(CQueryCmdHandler *)arg;
    self.writeStatusHeader();       //Master Status header
    self.writeLoadBalanceHeader();  //Ts Load Balance header
    for(;;){
        sleep(self.masterStatsTimeInterval_);
        self.writeStatus();         //Master Status
        self.writeLoadBalance();    //Ts Load Balance
    }
    return 0;
}
